
/**********************************************************************************
*
*	文件名称：ShowBMP.c
* 	文件作用：输入指定参数将指定BMP图片显示到指定位置
* 	文件作者：WSY
* 	修改日期：2023.12.25    搭建了框架，但是显示时候有问题
* 	修改日期：2023.12.26    修复了打开图片段错误bug，但是依旧不能做到缩放图片
*  	注意事项：
*
*	版权声明：CopyRight (c)  @cecelmx.126.com  All Right Reserved
* ********************************************************************************/

#include "showImg.h"
#include "head.h"

/// @brief 输入指定参数，可将指定路径BMP图片按指定大小显示到LCD指定位置
/// @param imgPath 文件路径
/// @param lcd_mmap LCD显存地址
/// @param start_x 起始x位置
/// @param start_y 起始y位置
/// @param mode    模式选择，如果是0则是缩略图模式，宽度和高度都将缩小为设备宽度的1/4
/// @return        如果成功返回1，失败返回-1
int showImgBmp( char * imgPath, int * lcd_mmap, int start_x, int start_y,int mode)
{
    
	/*1打开图片*/
	int fb = open(imgPath, O_RDWR);
    if(-1 == fb )
    {
        printf("打开图片失败！\n");
        return -1;
    }

    int width;
    //2使用偏移函数偏移到指定位置,并读取图片信息
    lseek(fb, 18 ,SEEK_SET);
    //使用读取函数读取当前位置信息
 
    int is_read = read(fb , &width, 4);
    if(-1 == is_read)
    {
        printf("未读取到有效数据\n");
        close(fb);

    }
    
    int height;
    //使用偏移函数偏移到指定位置
    lseek(fb, 22 ,SEEK_SET);
    //使用读取函数读取当前位置信息
 
    is_read = read(fb , &height, 4);
    if(-1 == is_read)
    {
        printf("未读取到有效数据\n");
        close(fb);

    }
    
    printf("位图宽度为：%d 字节\n" , width);
    printf("位图高度为：%d 字节\n" , height);

    /*定义一个基本宽度值fix_x*/
    int fix_x = (LCD_WIDTH / 4);

    /*定义变量来存储间隔，如果不是缩放模式，也无所谓*/

    /*定义变量来装目标*/
    int target_width = width; // 设置起始目标宽度
    int original_width = width ; // 获取图片的宽度

    int target_height = height; // 设置起始目标高度
    int original_height= height ; // 获取图片的高度

    int interval_width = 0;   //设置起始宽度间隔
    int interval_height = 0;  //设置起始高度间隔

    /*3.如果模式是缩略图模式，则将图片缩略到设备宽度1/4的正方形图片*/
    if (SHOW_MODE_TL == mode)
    {
       /*那就是缩放模式*/
       /*那么将图片宽度和缩放到设备宽度1/4*/
       /*那么就要将宽度和高度的间隔调好，按照这个间隔即可将bmp图片缩放*/
       //4.5如果宽度和高度超出限制，那么宽度和高度等于800和480
        /* 设置缩放比例 */

        /*计算要放大n倍还是缩减n倍*/
        target_width = fix_x;  // 目标宽度
        target_height = fix_x;  // 目标高度
       
    
    /*定义宽度的间隔值*/
        // 如果原始宽度小于目标宽度，放大特定比率
        interval_width = (original_width / target_width) > 1 ? (original_width / target_width)-1 : 0;
            
        

        /*定义高度的间隔值*/
    
        interval_height = (original_width/target_height) > 0 ?(original_width/target_height)-1 : 0;
           

        /*将缩放后的宽和高进行设置*/
        /*如果是大图模式则不受影响*/
        printf("本次宽度的间隔为：%d ,高度间隔为：%d\n",interval_width,interval_height);
    
    }
    
	
	//4.8 确认补全的宽度
    /*如果大于设备宽度和高度则进行裁剪*/
    target_height = target_height >= LCD_HEIGHT ? LCD_HEIGHT : target_height;
    target_width = target_width >= LCD_WIDTH ? LCD_WIDTH : target_width;

	int n = width % 4;
	int width_new = width + (4 - n) % 4 ;
	printf("修改后的位图宽度为：%d 字节\n" , target_width);
    printf("修改后的位图高度为：%d 字节\n" , target_height);
    printf("每行的缓冲区大小为：%d 字节\n" , width_new);


	lseek(fb , 54, SEEK_SET);
		
	// }
    /*定义三个变量来构造循环遍历LCD屏幕的每一个像素点*/
	int x, y, j = 0;

    /*读取时候还是读取完每一行所有像素*/
	char img_bf[width_new * 3];

    /*加上边界处理*/
    int stop_y = 0;    /*如果stop_y大于图片原本宽度则停止读取*/
    int stop_x = 0;    /*如果stop_x大于图片原本宽度则停止写入*/
    int stop_lcd = 0;  /*如果stop_lcd大于LCD宽度则停止写入*/

    for (y = LCD_HEIGHT-1 ; y >= 0; y--)
    {
		if (y < target_height)
		{
            //读取到一行数据后，如果在图形宽度的范围内，将数据怼进开发板
			int if_read = read(fb , img_bf, width*3);
        
            /*如果是缩略图模式则进行偏移处理，如果是大图模式则跳过处理*/
            if (mode = SHOW_MODE_TL)
            {
                stop_y += interval_height ;
                stop_x = 0;
                if (stop_y + target_height >= height)
                {
                    printf("此张bmp图片已经读完!\n");
                    break;
                }
             
            /*偏移间隔行，可以将图片高度缩小，每次跳过间隔行*/
            lseek(fb, interval_height*width, SEEK_CUR);
            }
            
           
			j=0;
		}
		
        for (x = 0; x < LCD_WIDTH; x++)
        {
            // 把BMP图片的每个像素点和LCD屏幕每个像素点进行转换
            // BMP存储顺序是从下到上，从左到右

			//如果在图像的高度范围内，读取每一行图形数据
			if(x <  target_width && (y < target_height) )
			{
                /*将开发板的像素点记录下来做边界处理*/
                //stop_lcd = *(lcd_mmap+y*LCD_WIDTH+x+(start_y*LCD_HEIGHT)+start_x);
                // if (stop_lcd >= LCD_HEIGHT*LCD_WIDTH*4)
                // {
                //     printf("屏幕满了，请稍后再试试吧！\n");
                //     return -1;
                // }
                

                /*开始写入数据*/
                *(lcd_mmap+y*LCD_WIDTH+x+(start_y*LCD_WIDTH)+start_x) = img_bf[j] | (img_bf[j+1]<<8) | (img_bf[j+2]<<16); 

                /*如果是缩略图模式则做边界处理，大图模式则不用*/
                if (mode = SHOW_MODE_TL)
                {
                    j+=(interval_width*3);
                   /*将图片宽度像素点记录下来做边界处理*/
                    stop_x = j;
                    if (stop_x >= width)
                    {
                        printf("写入每行颜色分量错误!\n");
                        break;
                    }
                    continue;
                }
                
                /*如果是缩放的话，要跳过间隔宽才行，每一个像素点是3个字节，所以每次跳过3个字节*/
				j+=3;
			}

			
        }
    }

	printf("__%d__\n",__LINE__);

	//7.解关闭文件
	close(fb);

	return 1;
}